import fs from "fs-extra";
import path from "path";
import { CmdOption, TCheckI18nRule } from "../CmdOption.js";
import { toolchain } from "../toolchain.js";
import { EFileErrorType, alertErrorFile, emphasize, sendBuildFailureAlert, sendRobotMsg } from "../tools/alert.js";
import { Cmd, ExecuteError } from "../tools/Cmd.js";
import { findOption, setOption } from "../tools/vendor.js";

const enum EFormatErr {
    RichFormatSlashPairErr = '富文本#配对错误',
    HtmlFormatErr = 'html格式错误',
    RichFormatErr = '富文本格式错误'
}

declare interface IFormatErr {
    local: string,
    errors: EFormatErr[]
}

declare interface IMissedFormats {
    local: string,
    fmts: string[]
}

declare interface IReport {
    noLocals: string[],
    missedFmts: IMissedFormats[],
    fmtErrors: IFormatErr[],
    termCNs: string[],
    termENs: string[]
}

declare interface IReportDoc {
    noTranslators: string[],
    concatStrErrors: string[],
    jsonSafeErrors: string[],
    langs: Record<string, IReport>
}

export declare interface I18NOut { localizeParams: string[], outputRoot: string, newOutput: boolean, autoTransFailedCnt: number, hasError: boolean, report?: IReportDoc }

export class I18N {
    public async prepareI18n(): Promise<void> {
        let pt = toolchain.params.projectType;
        const xlsRoot = toolchain.params.svn.urlMap.xls[pt];
        const serverscriptPath = path.join(toolchain.params.workSpacePath, '..', 'serverscript');
        if(!fs.existsSync(serverscriptPath)) {
            console.log("check out server script...");
            await fs.ensureDir(serverscriptPath);
            await toolchain.svnClient.checkout(xlsRoot + '/Develop/script', serverscriptPath);
        } else {
            console.log("update server script...");
            await toolchain.svnClient.cleanup(true, serverscriptPath);
            await toolchain.svnClient.revert(serverscriptPath);
            await toolchain.svnClient.update(serverscriptPath);
        }

        const servercfgPath = path.join(toolchain.params.workSpacePath, '..', 'servercfg');
        if(!fs.existsSync(servercfgPath)) {
            console.log("check out server cfg...");
            await fs.ensureDir(servercfgPath);
            await toolchain.svnClient.checkout(xlsRoot + '/Develop/bin/Server', servercfgPath);
        } else {
            console.log("update server cfg...");
            await toolchain.svnClient.cleanup(true, servercfgPath);
            await toolchain.svnClient.revert(servercfgPath);
            await toolchain.svnClient.update(servercfgPath);
        }
    }

    public async runI18N(cmdOption: CmdOption, mode: 'S' | 'R'): Promise<I18NOut | null> {
        const channelCfg = toolchain.params.channelCfg;
        if(!channelCfg.localize) return null;

        let localizeParams: string[] = [];
        if (channelCfg['localize-params']) {
            localizeParams = channelCfg['localize-params'].split(/\s+/);
        }
            
        console.log('@@ localize');
        const outputRoot = path.join(toolchain.params.workSpacePath, channelCfg['localize-output'] || 'tools/i18n/dictionary/tw');
        let newOutput = false;
        if (!fs.existsSync(outputRoot)) {
            newOutput = true;
            await fs.ensureDir(outputRoot);
        }

        // 忽略翻译错误，让其执行结束，以免因个别翻译错误导致整个翻译没有执行的问题
        // --langs要使用所有语言，而不能根据具体包的配置，否则发热更的时候，由于只指定一个gameid，会导致部分语言翻译没有执行
        const cmdParams = ['-s', toolchain.params.workSpacePath, '-o', outputRoot, `-${mode}`, '--silent', '-x', 'prepend', '--individual', '--ignore-errors'].concat(setOption(localizeParams, '--langs', toolchain.params.allLangs.join(',')));
        if (!cmdParams.includes('-l')) {
            cmdParams.push('-l');
        }
        const template = findOption(localizeParams, '-d');
        if (!template) {
            cmdParams.push('-d', 'unity');
        }

        const cmd = new Cmd();
        let catchError = 0, fatal = false;
        const errMsgs: string[] = [], warnMsgs: string[] = [];
        let errorCode = await cmd.runNodeModule('unity-i18n', cmdParams).catch(async (e: ExecuteError)=>{
            if (e.error) {
                console.error(e.error);
                if (e.error instanceof Error) {
                    
                }
            }
            catchError = e.code;
            fatal = true;
        });
        if (catchError != 0) errorCode = catchError;

        const mentionList: string[] = [];
        const checkErrorTypes = cmdOption.checkI18n ? cmdOption.checkI18n.split(',') as TCheckI18nRule[] : null;

        // 捕获js报错
        const jsemch = cmd.output.match(/(?:EvalError|RangeError|ReferenceError|SyntaxError|TypeError|URIError|AggregateError|InternalError): [^\r\n]+/);
        if (jsemch) {
            fatal = true;
            errMsgs.push(jsemch[0]);
        }

        // 分析报告文件
        let report: IReportDoc | undefined = undefined;
        const reportFile = path.join(outputRoot, 'report.json');
        if (fs.existsSync(reportFile)) {
            report = await fs.readJSON(reportFile) as IReportDoc;
            if (report.concatStrErrors.length > 0) {
                fatal = true;
                errMsgs.push(`${emphasize('拼接错误')}Concat error (${report.concatStrErrors.length}): ${report.concatStrErrors[0]}`);
                const mch = report.concatStrErrors[0].match(/请使用uts.format! (\S+)(?=:\d+:\d+)/);
                if (mch != null) {
                    const who = await alertErrorFile(mch[1], EFileErrorType.CodeError, mch[0]);
                    mentionList.push(who);
                }
                // await sendBuildFailureAlert('前台注意，因代码中包含拼接字符串导致构建失败');
            }

            if (report.jsonSafeErrors.length > 0) {
                fatal = true;
                errMsgs.push(`${emphasize('JSON错误')}JSON error (${report.jsonSafeErrors.length}): ${report.jsonSafeErrors[0]}`);
            }

            const missedFmts: string[] = [], fmtErrors: string[] = [], termCNs: string[] = [], termENs: string[] = [], noLocals: string[] = [];
            for (const lang in report.langs) {
                const rpt = report.langs[lang];
                if (rpt.missedFmts.length > 0) {
                    missedFmts.push(`${lang}(${rpt.missedFmts.length})`);
                }
                if (rpt.fmtErrors.length > 0) {
                    fmtErrors.push(`${lang}(${rpt.fmtErrors.length})`);
                }
                if (rpt.termCNs.length > 0) {
                    termCNs.push(`${lang}(${rpt.termCNs.length})`);
                }
                if (rpt.termENs.length > 0) {
                    termENs.push(`${lang}(${rpt.termENs.length})`);
                }
                if (rpt.noLocals.length > 0) {
                    noLocals.push(`${lang}(${rpt.noLocals.length})`);
                }
            }
            if (missedFmts.length > 0) {
                if (checkErrorTypes?.includes('FormatMissing')) {
                    fatal = true;
                }
                errMsgs.push(`${emphasize('格式丢失')}Format missing: ${missedFmts.join(', ')}`);
            }
            if (fmtErrors.length > 0) {
                if (checkErrorTypes?.includes('FormatError')) {
                    fatal = true;
                }
                errMsgs.push(`${emphasize('格式错误')}Format error: ${fmtErrors.join(', ')}`);
            }
            if (termCNs.length > 0) {
                if (checkErrorTypes?.includes('TermCN')) {
                    fatal = true;
                }
                errMsgs.push(`${emphasize('夹带中文')}TermCN error: ${termCNs.join(', ')}`);
            }
            if (termENs.length > 0) {
                if (checkErrorTypes?.includes('TermEN')) {
                    fatal = true;
                }
                errMsgs.push(`${emphasize('夹带英文')}TermEN error: ${termENs.join(', ')}`);
            }
            if (noLocals.length > 0) {
                // 没有翻译不导致构建失败
                warnMsgs.push(`${emphasize('没有翻译')}No local: ${noLocals.join(', ')}`);
            }
        }

        if (errorCode != 0 || errMsgs.length > 0) {
            let buildMsg = `@所有人 注意，翻译失败，错误码：${errorCode}，点击下方日志搜索:`;
            if (errMsgs.length > 0) {
                buildMsg += '\n' + errMsgs.join('\n');
            }
            if (warnMsgs.length > 0) {
                buildMsg += '\n' + warnMsgs.join('\n');
            }
            if (fatal) {
                // publish无论如何都报错
                await sendBuildFailureAlert(buildMsg);
                const responsor = toolchain.params.channelCfg['localize-responsor'];
                if (responsor) mentionList.push(responsor);
                if (mentionList.length > 0) {
                    await sendRobotMsg('text', '快给我改了！', mentionList.join(','));
                }
                process.exit(1);
            } else {
                toolchain.buildMessages.push(buildMsg);
                toolchain.appendLogURL = true;
            }
        } else {
            if (warnMsgs.length > 0) {
                let buildMsg = `@所有人 注意，翻译存在问题，点击下方日志搜索:`;
                buildMsg += '\n' + warnMsgs.join('\n');
                toolchain.buildMessages.push(buildMsg);
                toolchain.appendLogURL = true;
            }
        }

        let autoTransFailedCnt = 0;
        const mch = cmd.output.match(/Auto translation finished, success: \d+, failed: (\d+)/);
        if (mch != null) {
            autoTransFailedCnt = Number(mch[1]);
        }
        return { localizeParams, outputRoot, newOutput, autoTransFailedCnt, hasError: errMsgs.length > 0, report };
    }
}
